/*!
 * uQRCode-v2.3.6 (https://github.com/Sansnn/uQRCode)
 * API https://github.com/Sansnn/uQRCode/blob/master/README.md
 * @license MIT
 */
(function(global, factory) {
	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
		typeof define === 'function' && define.amd ? define(factory) :
		(global.uQRCode = factory());
}(this, (function() {
	'use strict';

	/**
	 * 预计算
	 */

	/*---------------------------------------------------------------- Gf256 start ----------------------------------------------------------------*/
	/**
	 * Gf256(2^8)的对数和反对数
	 * 伽罗瓦域
	 */
	class Gf256 {
		constructor() {
			/* 生成多项式 */
			this.generatorPolynomial = [1, 1, 1, 0, 1, 1, 0, 1, 1];

			/* 对数 */
			this.log = new Array(256);

			/* 反对数 */
			this.antilog = new Array(256);

			this.init();
		}

		/**
		 * 初始化
		 */
		init() {
			let antilog = new Array(255);

			/* 计算反向对数 */
			antilog[0] = 1;
			for (var i = 1; i < 255; i++) {
				let num = antilog[i - 1] << 1;
				if (num >= 256) {
					num = num ^ 285;
				}
				antilog[i] = num;
			}

			/* 计算对数 */
			for (var i = 0; i < 255; i++) {
				this.log[antilog[i]] = i;
			}
		}

		/**
		 * 对数
		 * @param {Object} n
		 */
		getLog(n) {
			return this.log[n];
		}

		/**
		 * 反对数
		 * @param {Object} n
		 */
		getAntilog(n) {
			return this.antilog[n];
		}

		/**
		 * 乘
		 * @param {Object} x
		 * @param {Object} y
		 */
		multiply(x, y) {
			if (x == 0 || y == 0) {
				return 0;
			}
			return this.antilog[(this.log[x] + this.log[y]) % 255];
		}

		/**
		 * 除
		 * @param {Object} x
		 * @param {Object} y
		 */
		division(x, y) {
			if (x == 0) {
				return 0;
			}
			if (y == 0) {
				throw 'y不能为0';
			}
			return this.antilog[(this.log[x] - this.log[y] + 255) % 255];
		}

		/**
		 * 获取生成多项式
		 * @param {Object} num 误差纠正码数量
		 */
		getGeneratorPolynomial(num) {
			let generatorPolynomial = [1];
			for (var i = 0; i < num; i++) {
				generatorPolynomial = this.polynomialMultiply(generatorPolynomial, [1, this.antilog[i]]);
			}
			return generatorPolynomial;
		}

		/**
		 * 多项式乘法
		 * @param {Object} p1
		 * @param {Object} p2
		 */
		polynomialMultiply(p1, p2) {
			let result = new Array(p1.length + p2.length - 1);
			for (var i = 0; i < p1.length; i++) {
				for (var j = 0; j < p2.length; j++) {
					let value = this.multiply(p1[i], p2[j]);
					if (result[i + j] == null) {
						result[i + j] = value;
					} else {
						result[i + j] = result[i + j] ^ value;
					}
				}
			}
			return result;
		}

		/**
		 * 多项式除法
		 * @param {Object} p1
		 * @param {Object} p2
		 */
		polynomialDivision(p1, p2) {
			let result = new Array(p1.length);
			for (var i = 0; i < p1.length; i++) {
				result[i] = p1[i];
			}

			for (var i = 0; i <= result.length - p2.length; i++) {
				let ratio = this.division(result[i], p2[0]);
				for (var j = 0; j < p2.length; j++) {
					result[i + j] = result[i + j] ^ this.multiply(p2[j], ratio);
				}
			}

			return result.slice(result.length - p2.length + 1, result.length);
		}
	}
	/*---------------------------------------------------------------- Gf256 end ----------------------------------------------------------------*/

	/**
	 * 预计算
	 */
	let gf256 = new Gf256();

	/**
	 * 工具
	 */
	const utils = {
		/**
		 * 获取utf8的字节长度
		 */
		getUTF8Bytes: function(str) {
			let bytes = [];
			for (let i = 0; i < str.length; i++) {
				let code = str.charCodeAt(i);
				if (code < 0x80) { // 单字节
					bytes.push(code);
				} else if (code < 0x800) { // 双字节
					bytes.push(0xC0 | (code >> 6));
					bytes.push(0x80 | (code & 0x3F));
				} else if (code < 0x10000) { // 三字节
					bytes.push(0xE0 | (code >> 12));
					bytes.push(0x80 | ((code >> 6) & 0x3F));
					bytes.push(0x80 | (code & 0x3F));
				} else { // 四字节
					bytes.push(0xF0 | (code >> 18));
					bytes.push(0x80 | ((code >> 12) & 0x3F));
					bytes.push(0x80 | ((code >> 6) & 0x3F));
					bytes.push(0x80 | (code & 0x3F));
				}
			}
			return bytes;
		}
	};

	/**
	 * 纠错等级
	 */
	const errorCorrectionLevel = {
		/* 低 */
		L: {
			bit: '01'
		},
		/* 中 */
		M: {
			bit: '00'
		},
		/* 良 */
		Q: {
			bit: '11'
		},
		/* 高 */
		H: {
			bit: '10'
		}
	};

	/**
	 * 位置探测图形
	 * 行、列的二进制表示
	 */
	const findPattern = {
		/* 位置探测图形 */
		pattern: [
			[1, 1, 1, 1, 1, 1, 1],
			[1, 0, 0, 0, 0, 0, 1],
			[1, 0, 1, 1, 1, 0, 1],
			[1, 0, 1, 1, 1, 0, 1],
			[1, 0, 1, 1, 1, 0, 1],
			[1, 0, 0, 0, 0, 0, 1],
			[1, 1, 1, 1, 1, 1, 1]
		],
		/* 分隔符 */
		separator: [0, 0, 0, 0, 0, 0, 0],
		/* 定位图（时序） */
		timing: [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
			0, 1
		]
	};

	/**
	 * 位置校正图形
	 */
	const alignmentPattern = {
		/* 位置校正图形 */
		pattern: [
			[1, 1, 1, 1, 1],
			[1, 0, 0, 0, 1],
			[1, 0, 1, 0, 1],
			[1, 0, 0, 0, 1],
			[1, 1, 1, 1, 1]
		]
	};

	var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !==
		'undefined' ? self : {};

	function createCommonjsModule(fn, module) {
		return module = {
			exports: {}
		}, fn(module, module.exports), module.exports;
	}

	var version = createCommonjsModule(function(module, exports) {
		/**
		 * 版本
		 */
		exports.VERSIONS = [{
			version: 1, // 版本
			size: 21, // 尺寸
			alignmentPattern: [], // 位置校正图形的中心坐标
			errorCorrection: { // 每个块的码字数(总数/数据)
				L: {
					codewords: 26, // 纠错码+数据码
					dataCodewords: 19 // 数据码
				},
				M: {
					codewords: 26,
					dataCodewords: 16
				},
				Q: {
					codewords: 26,
					dataCodewords: 13
				},
				H: {
					codewords: 26,
					dataCodewords: 9
				}
			}
		}];
	});

	/**
	 * 格式信息
	 */
	const formatInfo = {
		/* 格式信息(含掩码) */
		string: '101010000010010',

		/* 多项式 */
		polynomial: '10100110111',

		/* 异或, 用于计算格式信息的纠错码 */
		xor: '101010000010010'
	};

	/**
	 * 掩码
	 */
	const maskPattern = {
		/* 掩码版本 */
		TEST_1: {
			bit: '000',
			test: (i, j) => {
				return (i + j) % 2 == 0;
			}
		}
	};

	/**
	 * 纠错码
	 */

	class ErrorCorrectionCoding {
		constructor() {

		}

		/**
		 * 获取纠错码
		 * @param {Object} dataCodewords 数据码
		 * @param {Object} num 纠错码数量
		 */
		getErrorCorrectionCodewords(dataCodewords, num) {
			let data = new Array(dataCodewords.length + num);
			for (let i = 0; i < dataCodewords.length; i++) {
				data[i] = dataCodewords[i];
			}
			let generatorPolynomial = gf256.getGeneratorPolynomial(num);
			let result = gf256.polynomialDivision(data, generatorPolynomial);
			return result;
		}
	}

	/**
	 * 纠错码
	 */
	let errorCorrectionCoding = new ErrorCorrectionCoding();

	/**
	 * 数据编码
	 */
	const dataEncoding = {
		/**
		 * 编码
		 * @param {Object} data 字符串
		 */
		encode(data, version$$1, errorCorrectionLevel$$1) {
			let dataCodewords = this.getBytes(data);
			let result = this.getBits(dataCodewords);
			return result;
		},

		/**
		 * 获取字节
		 * @param {Object} data 字符串
		 */
		getBytes: function(data) {
			let bytes = utils.getUTF8Bytes(data);
			return bytes;
		},

		/**
		 * 获取二进制
		 * @param {Object} dataCodewords 字节数组
		 */
		getBits: function(dataCodewords) {
			let bits = '';
			for (let i = 0; i < dataCodewords.length; i++) {
				let bin = dataCodewords[i].toString(2);
				bits += '00000000'.substring(0, 8 - bin.length) + bin;
			}
			return bits;
		}
	};

	/**
	 * 数据分析
	 */
	const dataAnalysis = {
		/**
		 * 获取数据类型
		 * @param {Object} data
		 */
		getType(data) {
			return '8bit';
		}
	};

	let errorCorrectionCoding$1 = new errorCorrectionCoding();

	/**
	 * 二维码
	 * @param {Object} options
	 * {
	 *   text: 'https://uqrcode.cn/doc', // 必填
	 *   size: 256, // 尺寸，不填写默认256
	 *   margin: 10, // 边距，不填写默认10
	 *   errorCorrectionLevel: 'L', // 纠错等级，不填写默认为L
	 *   maskPattern: 1, // 掩码，不填写默认1
	 *   version: 1, // 版本，不填写默认1
	 *   foregroundColor: '#000000', // 前景色，不填写默认#000000
	 *   backgroundColor: '#ffffff' // 背景色，不填写默认#ffffff
	 * }
	 */
	class QRCode {
		constructor(options) {
			this.options = options;

			/* 获取版本信息 */
			this.versionInfo = this.getVersionInfo(this.options.version);

			/* 获取尺寸 */
			this.size = this.versionInfo.size;

			/* 数据分析 */
			this.dataType = dataAnalysis.getType(this.options.text);

			/* 获取数据编码 */
			this.dataCodewords = dataEncoding.encode(this.options.text);

			/* 获取纠错等级 */
			let errorCorrection = this.versionInfo.errorCorrection[this.options.errorCorrectionLevel || 'L'];

			/* 获取数据码(数据+纠错) */
			let dataCodewords = this.getDataCodewords(this.dataCodewords, errorCorrection);

			/* 获取原始矩阵 */
			let modules = this.getModules(dataCodewords);

			/* 获取掩码 */
			let maskPattern$$1 = this.getMaskPattern(modules);
			for (let i = 0; i < this.size; i++) {
				for (let j = 0; j < this.size; j++) {
					modules[i][j] = modules[i][j] ^ maskPattern$$1[i][j];
				}
			}

			/* 格式信息 */
			let formatInfo$$1 = this.getFormatInfo(this.options.errorCorrectionLevel, this.options.maskPattern);
			/* 左上角 */
			for (let i = 0; i < 8; i++) {
				modules[i][8] = modules[i][8] ^ formatInfo$$1[i];
				if (i > 5) {
					modules[i + 1][8] = modules[i + 1][8] ^ formatInfo$$1[i];
				}
			}
			for (let i = 8; i > 0; i--) {
				modules[8][i - 1] = modules[8][i - 1] ^ formatInfo$$1[8 - i];
				if (i > 6) {
					modules[8][i - 2] = modules[8][i - 2] ^ formatInfo$$1[8 - i];
				}
			}
			/* 右上角、左下角 */
			for (let i = 0; i < 15; i++) {
				modules[this.size - 1 - i][8] = modules[this.size - 1 - i][8] ^ formatInfo$$1[i];
				modules[8][this.size - 1 - i] = modules[8][this.size - 1 - i] ^ formatInfo$$1[i];
			}

			this.modules = modules;
		}

		/**
		 * 获取版本信息
		 * @param {Object} version
		 */
		getVersionInfo(version$$1) {
			for (let i = 0; i < version.VERSIONS.length; i++) {
				let versionInfo = version.VERSIONS[i];
				if (versionInfo.version == version$$1) {
					return versionInfo;
				}
			}
		}

		/**
		 * 获取数据码(数据+纠错)
		 * @param {Object} dataCodewords
		 * @param {Object} errorCorrection
		 */
		getDataCodewords(dataCodewords, errorCorrection) {
			let result = [];
			/* 纠错码 */
			let errorCorrectionCodewords = errorCorrectionCoding$1.getErrorCorrectionCodewords(dataCodewords, errorCorrection.codewords -
				errorCorrection.dataCodewords);

			/* 数据码 */
			for (var i = 0; i < errorCorrection.dataCodewords.length; i++) {
				result.push(errorCorrection.dataCodewords[i]);
			}
			/* 纠错码 */
			for (var i = 0; i < errorCorrectionCodewords.length; i++) {
				result.push(errorCorrectionCodewords[i]);
			}
			return result;
		}

		/**
		 * 获取原始矩阵
		 * @param {Object} dataCodewords
		 */
		getModules(dataCodewords) {
			let modules = new Array(this.size);
			for (let i = 0; i < this.size; i++) {
				modules[i] = new Array(this.size);
			}

			/* 位置探测图形 */
			this.addFindPattern(modules, 0, 0);
			this.addFindPattern(modules, this.size - 7, 0);
			this.addFindPattern(modules, 0, this.size - 7);

			/* 分隔符 */
			this.addSeparator(modules);

			/* 位置校正图形 */
			this.addAlignmentPattern(modules);

			/* 定位图（时序） */
			this.addTiming(modules);

			/* 将数据码填充到矩阵中 */
			this.addData(modules, dataCodewords);
			return modules;
		}

		/**
		 * 添加位置探测图形
		 * @param {Object} modules
		 * @param {Object} x
		 * @param {Object} y
		 */
		addFindPattern(modules, x, y) {
			for (var i = 0; i < 7; i++) {
				for (var j = 0; j < 7; j++) {
					modules[x + i][y + j] = findPattern.pattern[i][j];
				}
			}
		}

		/**
		 * 添加分隔符
		 * @param {Object} modules
		 */
		addSeparator(modules) {
			for (var i = 0; i < 7; i++) {
				/* 左上角 */
				modules[7][i] = findPattern.separator[i];
				modules[i][7] = findPattern.separator[i];

				/* 右上角 */
				modules[this.size - 8][i] = findPattern.separator[i];
				modules[i][this.size - 8] = findPattern.separator[i];

				/* 左下角 */
				modules[7][this.size - 1 - i] = findPattern.separator[i];
				modules[this.size - 1 - i][7] = findPattern.separator[i];
			}
		}

		/**
		 * 添加位置校正图形
		 * @param {Object} modules
		 */
		addAlignmentPattern(modules) {
			let alignmentPatterns = this.versionInfo.alignmentPattern;
			for (let i = 0; i < alignmentPatterns.length; i++) {
				for (let j = 0; j < alignmentPatterns.length; j++) {
					let x = alignmentPatterns[i];
					let y = alignmentPatterns[j];
					if (modules[x][y] == null) {
						for (let k = 0; k < 5; k++) {
							for (let l = 0; l < 5; l++) {
								modules[x - 2 + k][y - 2 + l] = alignmentPattern.pattern[k][l];
							}
						}
					}
				}
			}
		}

		/**
		 * 添加定位图（时序）
		 * @param {Object} modules
		 */
		addTiming(modules) {
			for (var i = 8; i < this.size - 8; i++) {
				if (modules[6][i] == null) {
					modules[6][i] = findPattern.timing[i - 8];
				}
				if (modules[i][6] == null) {
					modules[i][6] = findPattern.timing[i - 8];
				}
			}
		}

		/**
		 * 将数据码填充到矩阵中
		 * @param {Object} modules
		 * @param {Object} dataCodewords
		 */
		addData(modules, dataCodewords) {
			let inc = -1;
			let row = this.size - 1;
			let bitIndex = 0;
			let byteIndex = 0;
			for (let col = this.size - 1; col > 0; col -= 2) {
				if (col == 6) {
					col--;
				}
				while (true) {
					for (let c = 0; c < 2; c++) {
						if (modules[row][col - c] == null) {
							let dark = false;
							if (byteIndex < dataCodewords.length) {
								dark = (((dataCodewords[byteIndex] >>> bitIndex) & 1) == 1);
							}
							modules[row][col - c] = dark;
							bitIndex++;
							if (bitIndex == 8) {
								byteIndex++;
								bitIndex = 0;
							}
						}
					}
					row += inc;
					if (row < 0 || this.size <= row) {
						row -= inc;
						inc = -inc;
						break;
					}
				}
			}
		}

		/**
		 * 获取掩码
		 * @param {Object} modules
		 */
		getMaskPattern(modules) {
			let maskPattern$$1 = new Array(this.size);
			for (let i = 0; i < this.size; i++) {
				maskPattern$$1[i] = new Array(this.size);
			}

			for (let i = 0; i < this.size; i++) {
				for (let j = 0; j < this.size; j++) {
					if (modules[i][j] != null) {
						let mask = maskPattern['TEST_' + this.options.maskPattern];
						if (mask.test(i, j)) {
							maskPattern$$1[i][j] = 1;
						} else {
							maskPattern$$1[i][j] = 0;
						}
					}
				}
			}
			return maskPattern$$1;
		}

		/**
		 * 获取格式信息
		 * @param {Object} errorCorrectionLevel
		 * @param {Object} maskPattern
		 */
		getFormatInfo(errorCorrectionLevel$$1, maskPattern$$1) {
			let formatInfo$$1 = errorCorrectionLevel[errorCorrectionLevel$$1].bit + maskPattern['TEST_' + maskPattern$$1].bit;
			let bits = parseInt(formatInfo$$1, 2);
			for (var i = 0; i < 10; i++) {
				bits = bits << 1;
				if (bits >>> 10) {
					bits = bits ^ 1335;
				}
			}

			let result = (parseInt(formatInfo.xor, 2) ^ ((parseInt(formatInfo$$1, 2) << 10) | bits)).toString(2);
			if (result.length < 15) {
				result = '000000000000000'.substring(0, 15 - result.length) + result;
			}
			return result;
		}
	}

	var umd = createCommonjsModule(function(module) {
		module.exports = {
			...{
				Gf256: Gf256,
				gf256: gf256
			},
			...{
				utils: utils
			},
			...{
				ErrorCorrectionLevel: errorCorrectionLevel
			},
			...{
				FindPattern: findPattern
			},
			...{
				AlignmentPattern: alignmentPattern
			},
			...version,
			...{
				FormatInfo: formatInfo
			},
			...{
				MaskPattern: maskPattern
			},
			...{
				ErrorCorrectionCoding: ErrorCorrectionCoding,
				errorCorrectionCoding: errorCorrectionCoding$1
			},
			...{
				DataEncoding: dataEncoding
			},
			...{
				DataAnalysis: dataAnalysis
			},
			...{
				QRCode: QRCode
			},

			make(options, callback) {
				if (options.canvasId) {
					/* uni-app、微信小程序 */
					const ctx = uni.createCanvasContext(options.canvasId, options.componentInstance);
					this.drawCanvas(ctx, options, (res) => {
						callback && callback(res);
					});
				} else if (options.context) {
					/* node-canvas */
					this.drawCanvas(options.context, options, (res) => {
						callback && callback(res);
					});
				} else {
					/* 纯js */
					let qrcode = new this.QRCode(options);
					callback && callback(qrcode.modules);
				}
			},

			drawCanvas(ctx, options, callback) {
				let qrcode = new this.QRCode(options);
				let modules = qrcode.modules;
				let tileW = (options.size || 256) / modules.length;
				let tileH = (options.size || 256) / modules.length;

				if (options.backgroundImage) {
					/* 绘制背景图 */
					ctx.drawImage(options.backgroundImage, 0, 0, options.size, options.size);
				} else {
					/* 绘制背景色 */
					ctx.setFillStyle(options.backgroundColor || '#ffffff');
					ctx.fillRect(0, 0, options.size, options.size);
				}

				/* 绘制二维码 */
				ctx.setFillStyle(options.foregroundColor || '#000000');
				for (var row = 0; row < modules.length; row++) {
					for (var col = 0; col < modules.length; col++) {
						if (modules[row][col]) {
							ctx.fillRect(col * tileW, row * tileH, tileW, tileH);
						}
					}
				}

				if (options.logo) {
					/* 绘制logo */
					let logoX = (options.size - options.logoSize) / 2;
					let logoY = (options.size - options.logoSize) / 2;
					ctx.drawImage(options.logo, logoX, logoY, options.logoSize, options.logoSize);
				}

				/* 在canvas上绘制 */
				ctx.draw(false, () => {
					/* uni-app、微信小程序 */
					if (options.canvasId) {
						uni.canvasToTempFilePath({
							canvasId: options.canvasId,
							success: function(res) {
								callback && callback(res.tempFilePath);
							},
							fail: function(err) {
								callback && callback(err);
							}
						}, options.componentInstance);
					} else {
						/* node-canvas */
						callback && callback();
					}
				});
			},
		};
	});

	return umd;

}))); 